#ifndef SPW_MOVE_IN_H_
#define SPW_MOVE_IN_H_
#include<type_traits>
#include <spw_config.h>

namespace spwstd {
namespace spwuti {

// addressof 返回真正的地址，重载&对象，位域，临时对象
template<typename T>
constexpr T* addressOf(T& arg){
    return reinterpret_cast<T*>(
        &const_cast<char&>(
            reinterpret_cast<const volatile char&>(arg)
        )
    );
}

template<typename T>
const T* addressOf(const T&&) = delete;

// move, 把一个值转换成rvalue
// 因为remove_reference，所以一定转换成右值返回
template<typename VT>
constexpr typename std::remove_reference<VT>::type&&
move(VT&& t) noexcept {
    return static_cast<typename std::remove_reference<VT>::type&&>(t);
}

// forward, 完美转发
// 因为引用折叠原因VT&&可能左值可能右值
// forward<T>(x), 把x强制转换为T&&, T为右值引用[几乎不会出现]或不是引用时，转为右值引用, 其他都是左值引用
// 通常用在使用通用类型为参数的函数模板中，想保留参数左右值属性并传入下一个函数
// forward返回值永远有引用属性
template<typename VT>
constexpr VT&& 
forward(typename std::remove_reference<VT>::type& t) noexcept {
    return static_cast<VT&&>(t);
}

template<typename VT>
constexpr VT&& 
forward(typename std::remove_reference<VT>::type&& t) noexcept {
    static_assert(!std::is_lvalue_reference_v<VT>, " is an lvalue reference type");
    return static_cast<VT&&>(t);
}

// 通用swap
// 类型必须一样, 可以隐式转换也不可以
template <typename VT>
inline void swap(VT& a, VT& b) {
    // a,b都是可赋值的, 可修改的
    // =不需要支持可移动
    // 但操作对象不可operator=delete移动操作，不然会匹配到delete的移动操作
    // Move(),得到右值引用。但=可以用复制操作
    VT tmp = spwuti::move(a);
    a = spwuti::move(b);
    b = spwuti::move(tmp);
}

// C数组特化
template <typename VT, spwconfig::size_t Nm>
inline void swap(VT (&a)[Nm], VT (&b)[Nm]) {
    for(spwconfig::size_t i=0; i<Nm; ++i) {
        spwuti::swap(a[i], b[i]);
    }
}
} // namespace spwuti

} // namespace spwstd
#endif // SPW_MOVE_IN_H_
